#include "threadpool_t.h"


threadpool_t::threadpool_t(void)
	:mini_thread_count(4)
{
	pull_task_fun =	std::bind(&threadpool_t::pull_task,
		this, std::placeholders::_1);
	thread_exit_fun = std::bind (&threadpool_t::thread_exit_pro,
		this, std::placeholders::_1);
}
threadpool_t::~threadpool_t(void)
{

}
void threadpool_t::add_task( task_t &task_ )
{
	thread_list_mutex.lock();
	assert(alive_thread_list.empty() == false);
	thread_ptr_t thread = alive_thread_list.front();
	uint32_t status = thread->get_status();
    task_ptr_t task  = std::make_shared<task_t>(task_);
	if (status == thread_t::suspend)
	{
		alive_thread_list.pop_front();
		alive_thread_list.push_back(thread);

		thread_list_mutex.unlock();

		thread->run(task);
		return;
	}
	else if(alive_thread_list.size() < max_thread_num)
	{
		create_a_new_thread();
		thread_list_mutex.unlock();
		task_queue.push_back(task);
	}
	else
	{
		thread_list_mutex.unlock();
		task_queue.push_back(task);
	}
	
}

void threadpool_t::init( uint32_t max_thread_num, uint32_t idle_timeout )
{
	static std::once_flag once;
	std::function<void(uint32_t,uint32_t)> init_once = std::bind(
		&threadpool_t::init_thread,this, 
		std::placeholders::_1,std::placeholders::_2);

	std::call_once(once,init_once,max_thread_num, idle_timeout);
}

void threadpool_t::init_thread( uint32_t max_thread_num_, uint32_t idle_timeout_)
{
	max_thread_num = max_thread_num_;
	idle_timeout = idle_timeout_;
	if (mini_thread_count > max_thread_num)
	{
		mini_thread_count = max_thread_num;
	}
	for (uint32_t i = 0 ; i < mini_thread_count ; ++i)
	{
		thread_t::pull_task_fun_t pull_task =
			std::bind(&threadpool_t::pull_task,this, std::placeholders::_1);

		thread_ptr_t thread = std::make_shared<thread_t>(next_tid(), 
			pull_task_fun, thread_exit_fun);

		alive_thread_list.push_back(thread);
		thread->start();
	}
}

bool threadpool_t::pull_task( task_ptr_t &task_ )
{
	return task_queue.pull_front(task_);
}

uint32_t threadpool_t::next_tid()
{
	static uint32_t tid = 0;
	return ++tid;
}

void threadpool_t::create_a_new_thread()
{
	thread_ptr_t thread ;
	if (dead_thread_list.empty())
	{
		thread= std::make_shared<thread_t>(next_tid(), pull_task_fun,
			thread_exit_fun);
	}
	else
	{
		thread = dead_thread_list.front();
		dead_thread_list.pop_front();
	}
	alive_thread_list.push_back(thread);
	thread->set_idle_timeout(idle_timeout);
	thread->start();
}

void threadpool_t::destroy()
{
	thread_list_mutex.lock ();
	while (alive_thread_list.empty () == false)
	{
		thread_ptr_t thread = alive_thread_list.front ();
		thread_list_mutex.unlock();
		
		thread->stop();
	
		thread_list_mutex.lock ();
	}
	thread_list_mutex.unlock ();

}

void threadpool_t::thread_exit_pro( uint32_t tid_ )
{
	lock_guard_t guard_lock (thread_list_mutex);
	thread_list_t::iterator it = alive_thread_list.begin ();
	for (;it != alive_thread_list.end (); ++it)
	{
		if ((*it)->get_tid () == tid_)
		{
			dead_thread_list.push_back (*it);
			alive_thread_list.erase (it);
			return;
		}
	}
	assert(false);
}
